#include "sal.h"
#include "ctc_const.h"
#include "ctc_pmem.h"
#include "ctc_warmboot.h"

uintptr pmem_addr[CTC_MAX_LOCAL_DEV_NUM] ={ 0 };
uint32 pmem_size[CTC_MAX_LOCAL_DEV_NUM] = { 0 };
uintptr sdb_pmem_addr[CTC_MAX_LOCAL_DEV_NUM] ={ 0 };
uint32 sdb_pmem_size[CTC_MAX_LOCAL_DEV_NUM] = { 0 };
uintptr pmem_addr_offset=0;
uint8 addr_offset_dir =0;

extern uintptr 
ctc_pmem_init(uint8 ldev, ctc_pmem_cfg_t *p_cfg)
{ 
#ifdef SDK_IN_USERMODE
   struct stat stat_buf;
   int32 fd;

  if(!p_cfg || ldev >= CTC_MAX_LOCAL_DEV_NUM)
  {
     return (uintptr)NULL;
  }

    fd = sal_open(p_cfg->file_name, O_RDWR | (p_cfg->create ?O_TRUNC : 0), 00777);
 
    if (fd != -1 && p_cfg->create) 
   {
        if (-1 == sal_ftruncate(fd, p_cfg->size))
        {
            sal_close (fd);
            return (uintptr)NULL;
        }
    }
    else if (-1 == fd)
    {
        /* existing file is not there, create new file */
        fd = sal_open(p_cfg->file_name,(O_CREAT | O_RDWR), 00777);
        if ( - 1 == fd)
        {
            return (uintptr)NULL;
        }
        /* when file created its size set to 0. Adjust it to the desired size */
        if (-1 == sal_ftruncate(fd, p_cfg->size))
        {
            sal_close (fd);
            return (uintptr)NULL;
        }
    }
    /* warm boot */
   else
   {
       if (0 == sal_fstat(fd, &stat_buf))
       {
           p_cfg->size = (uint32)stat_buf.st_size;
           if (0==p_cfg->size || - 1 == sal_ftruncate(fd, p_cfg->size))
           {
               sal_close (fd);
               return (uintptr)NULL;
           }
       }
    }
   /* memory map the file */
   if (0 == p_cfg->type)   /* for wb */
   {
      pmem_addr[ldev] = (uintptr)sal_mmap(NULL, p_cfg->size,  PROT_WRITE | PROT_READ,  MAP_SHARED, fd, 0);  
      pmem_size[ldev] = p_cfg->size;
   }
   else  /* for sdb */
   {
      sdb_pmem_addr[ldev] = (uintptr)sal_mmap(NULL, p_cfg->size,  PROT_WRITE | PROT_READ,  MAP_SHARED, fd, 0);      
      sdb_pmem_size[ldev] = p_cfg->size;
   }
   sal_close (fd);
#endif
   return p_cfg->type? sdb_pmem_addr[ldev] : pmem_addr[ldev];
}
extern int32
ctc_pmem_deinit(uint8 ldev)
{
#ifdef SDK_IN_USERMODE
   if( ldev <  CTC_MAX_LOCAL_DEV_NUM && pmem_size[ldev] )
   {
      sal_munmap((void *)pmem_addr[ldev],pmem_size[ldev]); 
   }
   if (ldev < CTC_MAX_LOCAL_DEV_NUM && sdb_pmem_size[ldev])
   {
      sal_munmap((void *)sdb_pmem_addr[ldev], sdb_pmem_size[ldev]); 
   }
#endif
   return 0;
}

extern int32
ctc_pmem_sync(uint8 ldev, uintptr  addr, uint32 size)
{
#ifdef SDK_IN_USERMODE
   if(size &&  ldev <  CTC_MAX_LOCAL_DEV_NUM 
     && (addr >=pmem_addr[ldev]) && ((addr + size) <= (pmem_addr[ldev] +pmem_size[ldev])))
   {
         sal_msync ((uint8*)addr ,size, MS_ASYNC);
   }
#endif
   return 0;
}

extern int32
ctc_pmem_remmap(uint8 ldev,ctc_wb_master_t *p_wb_master)
{
#ifdef SDK_IN_USERMODE
    char  file_name[32]={0}; 
    int32 fd = 0;
    void* tmp_addr = NULL;
    sal_sprintf(file_name,"ctc_pmem%d",ldev);
    ctc_pmem_sync(ldev,pmem_addr[ldev],pmem_size[ldev]);
    sal_munmap((void *)pmem_addr[ldev], pmem_size[ldev]);
    fd = sal_open(file_name, O_RDWR, 00777);
    if ( - 1 == fd)
    {
        return (uintptr)NULL;
    }
    if ( - 1 == sal_ftruncate(fd, p_wb_master->actual_size+ 0x400000))
    {
        sal_close (fd);
        return (uintptr)NULL;
    }
    tmp_addr = sal_mmap(NULL, p_wb_master->actual_size+0x400000,  PROT_WRITE | PROT_READ,  MAP_SHARED, fd, 0);/*rsv 4M bytes for pon and sc-oam */
    sal_close (fd);
    if(tmp_addr == (void*)-1)
    {
       return -1;
    }
    pmem_addr[ldev] = (uintptr)tmp_addr;
    pmem_size[ldev] = p_wb_master->actual_size+0x400000;
    p_wb_master->start_addr = pmem_addr[ldev];
    p_wb_master->sync_bmp = (uint32 *)pmem_addr[ldev];
    #endif
    return 0;
}

